Kratos 学习笔记

开发顺序

  1. 编写 proto 文件,定义 API
  2. 编写 internal/service 层的代码
    1. 验证请求
    2. 调用 biz 层业务逻辑,biz 层需要传入新的 Usecase
      1. 实现 biz 层调用的 data 层数据库操作实现
    3. 返回响应

如何在biz层使用配置文件

更改conf.proto

这里添加了App字段,记得添加消息到Bootstarp消息体中

syntax = "proto3";

// 略

message Bootstrap {
  Server server = 1;
  Data data = 2;
  App app = 3;
}

// 略

message App {
  string env = 1; // dev test prod

}

生成config代码

在项目根目录执行make config来自动生成配置文件代码

更改依赖注入相关代码

cmd/krathub/main.go中找到如下代码,添加bc.App结构体

	app, cleanup, err := wireApp(bc.Server, bc.Data, bc.App, logger)
	if err != nil {
		panic(err)
	}

随后在wire.go中添加一个名为*conf.App的依赖

// wireApp init kratos application.

func wireApp(*conf.Server, *conf.Data, *conf.App, log.Logger) (*kratos.App, func(), error) {
    panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, newApp))
}

生成依赖注入代码

在main函数的目录中执行wire来生成代码,这样我们自定义的配置文件才能传入进去

在biz层需要配置的地方添加依赖项

在我的代码internal/biz/auth.go中需要用到配置文件,所以需要做如下修改

// AuthUsecase is a Auth usecase.
type AuthUsecase struct {
	repo AuthRepo
	log  *log.Helper
	cfg  *conf.App  // 新增的依赖项,注意结构体名字不能搞错
}

// NewAuthUsecase new an auth usecase.                ↓这里就是方法所需依赖
func NewAuthUsecase(repo AuthRepo, logger log.Logger, cfg *conf.App) *AuthUsecase {
	return &AuthUsecase{
		repo: repo,
		log:  log.NewHelper(logger),
		cfg:  cfg,
	}
}

此时还没有再次执行依赖注入的程序,只是人为声明了依赖,wire并不知道我们在哪个层的哪个方法使用了我们在wire.go中添加的依赖。所以这个时候去查看cmd/krathub/wire_gen.go中的代码,可以发现wireApp方法已经有一个名为app *conf.App的形参,但是在下方的方法NewAuthUsecase中并没有引用这个形参。

// wireApp init kratos application.
func wireApp(confServer *conf.Server, confData *conf.Data, app *conf.App, logger log.Logger) (*kratos.App, func(), error) {              // ↑之前执行wire的时候已经有了这个形参
	db, err := data.NewDB(confData)
	if err != nil {
		return nil, nil, err
	}
	dataData, cleanup, err := data.NewData(db, confData, logger)
	if err != nil {
		return nil, nil, err
	}
	authRepo := data.NewAuthRepo(dataData, logger)   // ↓在执行wire前这里没有app参数 
	authUsecase := biz.NewAuthUsecase(authRepo, logger, app)
	authService := service.NewAuthService(authUsecase)
	grpcServer := server.NewGRPCServer(confServer, authService, logger)
	httpServer := server.NewHTTPServer(confServer, authService, logger)
	kratosApp := newApp(logger, grpcServer, httpServer)
	return kratosApp, func() {
		cleanup()
	}, nil
}

所以我们需要再次执行wire命令来重新生成依赖注入代码,这个过程熟悉之后,文中之前提到的初次依赖注入代码就可以不用执行命令,只要本次一次执行即可

使用配置文件

现在已经做完了所有工作,直接用以下代码即可获得所需配置

fmt.Println(uc.cfg.Env)

注意事项

新增业务须知

编写完新的业务之后需要在servicebizdata层的wire方法加入依赖,然后用wire生成代码,最后在serverhttpgrpc的定义方法中添加相应的service.xxxService才能正常上线业务

三个层的依赖注入代码
internal/service/service.go
var ProviderSet = wire.NewSet(NewAuthService, NewUserService)

internal/biz/biz.go
var ProviderSet = wire.NewSet(NewAuthUsecase, NewUserUsecase)

internal/data/data.go
var ProviderSet = wire.NewSet(NewData, NewDB, NewAuthRepo, NewUserRepo)

文件internal/server/http.go,grpc.go同理

// NewHTTPServer new an HTTP server.
func NewHTTPServer(c *conf.Server, auth *service.AuthService, user *service.UserService, logger log.Logger) *http.Server {
	var opts = []http.ServerOption{
		http.Middleware(
			recovery.Recovery(),
			tracing.Server(),
			logging.Server(logger),
			validate.Validator(),
			selector.Server(middleware.Auth()).Match(middleware.AuthWhiteListMatcher()).Build(),
		),
	}
	if c.Http.Network != "" {
		opts = append(opts, http.Network(c.Http.Network))
	}
	if c.Http.Addr != "" {
		opts = append(opts, http.Address(c.Http.Addr))
	}
	if c.Http.Timeout != nil {
		opts = append(opts, http.Timeout(c.Http.Timeout.AsDuration()))
	}
	srv := http.NewServer(opts...)
	authV1.RegisterAuthHTTPServer(srv, auth)
	userV1.RegisterUserHTTPServer(srv, user)
	return srv
}